2009/03/11

Recent entries from same category

  1. RapidJSON や simdjson よりも速いC言語から使えるJSONライブラリ「yyjson」
  2. コメントも扱える高機能な C++ 向け JSON パーサ「jsoncpp」
  3. C++ で flask ライクなウェブサーバ「clask」書いた。
  4. C++ 用 SQLite3 ORM 「sqlite_orm」が便利。
  5. zsh で PATH に相対パスを含んだ場合にコマンドが補完できないのは意図的かどうか。

readline使ってコマンドライン提供、curlで通信、結果をjson-cでパースまで作った。燃え尽きた。
追記
shebangから使えるようにした。
#!/usr/bin/dansh
以下コード // for MSVC: cl -I.. /Tp dansh.cpp curl.lib readline.lib ..\Release\json.lib
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
namespace json {
#include "json.h"
}
#define READLINE_STATIC
#include <readline/readline.h>
#include <curl/curl.h>
#define API_URL "http://api.dan.co.jp/perleval.cgi?c=callback&s="

typedef struct {
    char* data;     // response data from server
    size_t size;    // response size of data
} MEMFILE;

MEMFILE*
memfopen() {
    MEMFILE* mf = (MEMFILE*) malloc(sizeof(MEMFILE));
    mf->data = NULL;
    mf->size = 0;
    return mf;
}

void
memfclose(MEMFILE* mf) {
    if (mf->data) free(mf->data);
    free(mf);
}

size_t
memfwrite(char* ptr, size_t size, size_t nmemb, void* stream) {
    MEMFILE* mf = (MEMFILE*) stream;
    int block = size * nmemb;
    if (!mf->data)
        mf->data = (char*) malloc(block);
    else
        mf->data = (char*) realloc(mf->data, mf->size + block);
    if (mf->data) {
        memcpy(mf->data + mf->size, ptr, block);
        mf->size += block;
    }
    return block;
}

char*
memfstrdup(MEMFILE* mf) {
    char* buf = (char*) malloc(mf->size + 1);
    memcpy(buf, mf->data, mf->size);
    buf[mf->size] = 0;
    return buf;
}

char*
url_encode_alloc(const char* str, int force_encode) {
    const char* hex = "0123456789abcdef";

    char* buf = NULL;
    unsigned char* pbuf = NULL;
    int len = 0;

    if (!str) return NULL;
    len = strlen(str)*3;
    buf = (char*) malloc(len+1);
    memset(buf, 0, len+1);
    pbuf = (unsigned char*)buf;
    while(*str) {
        unsigned char c = (unsigned char)*str;
        if (c == ' ')
            *pbuf++ = '+';
        else if (c & 0x80 || force_encode) {
            *pbuf++ = '%';
            *pbuf++ = hex[c >> 4];
            *pbuf++ = hex[c & 0x0f];
        } else
            *pbuf++ = c;
        str++;
    }
    return buf;
}

void do_dan(const char* line) {
    char* source = url_encode_alloc(line, TRUE);
    char* url = (char*) malloc(strlen(API_URL) + strlen(source) + 1);
    strcpy(url, API_URL);
    strcat(url, source);

    MEMFILE* mf = memfopen();
    CURL* curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_URL, url);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, mf);
    CURLcode res = curl_easy_perform(curl);
    free(url);
    if (res == CURLE_OK) {
        char* data = memfstrdup(mf);
        memfclose(mf);

        // remove callback function
        char* ptr;
        ptr = strrchr(data, ')');
        if (ptr) *ptr = 0;
        ptr = strchr(data, '(');
        if (ptr) *ptr++ = 0;
        else ptr = data;

        json::json_object *obj = json::json_tokener_parse(ptr);
        if (!is_error(obj)) {
            json::json_object *result = json::json_object_object_get(obj, "result");
            if (!is_error(result)) {
                printf("%s\n", json::json_object_to_json_string(result));
                json_object_put(result);
            }
        }
        free(data);
    }
    curl_easy_cleanup(curl);
}

int main(int argc, char **argv)
{
    char* line = NULL;

    //json::mc_set_debug(1);
    if (argc == 2) {
        FILE* fp = fopen(argv[1], "rb");
        if (!fp) {
            perror("can't open file");
            exit(-1);
        }
        char buf[BUFSIZ];
        while (fgets(buf, sizeof(buf), fp)) {
            if (!line) {
                if (strncmp(buf, "#!", 2))
                    line = strdup(buf);
            } else {
                line = (char*) realloc(line, strlen(line) + strlen(buf) + 1);
                strcat(line, buf);
            }
        }
        fclose(fp);
        do_dan(line);
        free(line);
    }
    if (!isatty(fileno(stdin))) {
        char buf[BUFSIZ];
        while (fgets(buf, sizeof(buf), stdin)) {
            if (!line) {
                if (strncmp(buf, "#!", 2))
                    line = strdup(buf);
            } else {
                line = (char*) realloc(line, strlen(line) + strlen(buf) + 1);
                strcat(line, buf);
            }
        }
        do_dan(line);
        free(line);
    } else {
        while (line = readline("dan> ")) {
            do_dan(line);
            free(line);
        }
    }
    return 0;
}

参考文献: 404 Blog Not Found:Ajax - perlを実行するAPI
Posted at by